预加载 WASM
渲染 Rive 实例时,你的浏览器会发出网络请求到 https://unpkg.com/@rive-app/[email protected]/rive.wasm,该请求会获取一个 Web Assembly (WASM) 文件,其中包含用于构建渲染循环的 Rive 特定 API。unkpg 是一个全球 CDN,可以快速加载 NPM 包,在此情况下包括 WASM 文件。这使得在引入 Rive 基于 JS 的运行时时包体积更小,而只有在创建 Rive 实例时才加载 WASM。
自托管 Rive WASM
虽然 unpkg 应能快速提供 WASM,但你可能希望将 WASM 文件作为同源静态资源自行预加载和托管,原因包括:
- 严格掌控驱动 Rive 动画的 WASM 来源,而非依赖第三方 unpkg CDN
- 更快地初始化 Rive
- 能够控制
rive.wasm文件的缓存策略
如果你确实决定自行托管 WASM 文件,请注意以下几点:
rive.wasm文件的版本必须与 package.json 中的@rive-app包版本匹配——它们是成对构建的,版本不匹配会导致运行时渲染或功能异常。将版本号放在路径或文件名中(例如rive-2.40.1.wasm),并在更新依赖的同一提交中更新托管的文件。<link rel="preload">的 href 与传给setWasmUrl()的 URL 必须完全一致,否则预加载的字节会被丢弃,文件会被下载两次。参见下面的示例。- 以
application/wasmMIME 类型提供该文件——其他类型会让你脱离流式编译路径,降级到更慢的回退方案。 - 如果文件与页面位于不同源(例如 CDN 子域名),还需为你的页面源发送
Access-Control-Allow-Origin。 - 以
Cache-Control: public, max-age=31536000, immutable提供带版本的文件,并确 认你的 CDN 对 .wasm 应用了 brotli/gzip 压缩(某些 CDN 默认只压缩文本类型)。
在页面加载时初始化 Rive
如果你需要 Rive 在页面加载时立即可用于渲染图形(例如 hero 动画),我们建议同时预加载 rive.wasm 文件和实际的 .riv 文件,以便浏览器提前开始下载必要资源。在 JS 端,你可以使用 RuntimeLoader API 在页面上实例化 Rive 图形之前,提前开始下载并编译 WASM。另一个优化是提前 fetch .riv 文件并以 ArrayBuffer 形式获取字节,以便传递给 Rive 实例。
<!-- index.html -->
<!-- 尽早打开到 wasm CDN 的连接 -->
<!-- 如果你自行托管 WASM 文件,请将此处改为你的 CDN URL -->
<link rel="preconnect" href="https://unpkg.com" crossorigin />
<!-- 预加载运行时将请求的精确带版本 wasm URL。
版本必须与已安装的 @rive-app 包版本匹配,否则
运行时会重新 拉取该资源 -->
<!-- 如果你自行托管 WASM 文件,请将此处改为你服务器上 rive.wasm 的位置 -->
<link
rel="preload"
as="fetch"
crossorigin
href="https://unpkg.com/@rive-app/[email protected]/rive.wasm"
/>
<!-- 同时预加载主要的 hero .riv 文件 -->
<link rel="preload" as="fetch" crossorigin href="/assets/hero.riv" />
import { Rive, RuntimeLoader } from '@rive-app/canvas';
// (可选)仅当你在自己的服务器上托管 WASM 文件时才需要添加
// const WASM_URL = "https://cdn.example.com/assets/rive-2.40.1.wasm";
// RuntimeLoader.setWasmUrl(WASM_URL);
// 在页面加载时尽可能早地运行此 API,以开始编译 rive.wasm 文件
RuntimeLoader.awaitInstance().catch(() => {});
const heroFetch = fetch("/assets/hero.riv").then((r) => r.arrayBuffer());
// ... 稍后,在挂载时:
async function mountHero(canvas) {
const riveInstance = new Rive({
canvas,
buffer: await heroFetch,
stateMachine: "State Machine 1",
autoBind: true,
autoplay: true,
// ... 其他配置
});
}
特别鸣谢
特别感谢 Alex Barashkov 的原始博客文章启发了我们添加此技巧。
https://dev.to/alex_barashkov/optimization-techniques-for-rive-animations-in-react-apps-1a8p